package middleware

import (
	"log"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

const TraceIDKey = "trace_id"
const TraceIDHeader = "X-Trace-Id"

// Trace attaches a trace id to the request and response, and logs request lifecycle with it.
func Trace() gin.HandlerFunc {
    return func(c *gin.Context) {
        traceID := c.GetHeader(TraceIDHeader)
        if traceID == "" {
            traceID = uuid.New().String()
        }
        c.Set(TraceIDKey, traceID)
        c.Writer.Header().Set(TraceIDHeader, traceID)

        start := time.Now()
        path := c.Request.URL.Path
        method := c.Request.Method
        clientIP := c.ClientIP()

        // before
        log.Printf("level=info msg=\"request_start\" trace_id=%s method=%s path=%s ip=%s", traceID, method, path, clientIP)

        c.Next()

        // after
        status := c.Writer.Status()
        latency := time.Since(start)
        if len(c.Errors) > 0 {
            // use the last error message
            log.Printf("level=error msg=\"request_end\" trace_id=%s method=%s path=%s status=%d latency_ms=%d error=%q", traceID, method, path, status, latency.Milliseconds(), c.Errors.String())
        } else {
            log.Printf("level=info msg=\"request_end\" trace_id=%s method=%s path=%s status=%d latency_ms=%d", traceID, method, path, status, latency.Milliseconds())
        }
    }
}
